package main

import (
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"
)

type PageData struct {
	Files []string
}

var tmpl *template.Template

func main() {
	os.MkdirAll("upload/", 0755)
	tmpl = template.Must(template.ParseFiles("index.html"))

	http.HandleFunc("/upload", uploadHandler)
	http.Handle("/upload/", http.StripPrefix("/upload/", http.FileServer(http.Dir("upload/"))))
	http.HandleFunc("/delete", deleteHandler)
	http.HandleFunc("/", indexHandler)

	log.Fatal(http.ListenAndServe(":19999", nil))
}

func uploadHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	err := r.ParseMultipartForm(32 << 20)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	file, handler, err := r.FormFile("file")
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	defer file.Close()

	f, err := os.Create("upload/" + handler.Filename)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer f.Close()

	_, err = io.Copy(f, file)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	http.Redirect(w, r, "/", http.StatusFound)
}

func deleteHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	filename := r.FormValue("filename")
	if filename == "" {
		http.Error(w, "Filename is required", http.StatusBadRequest)
		return
	}

	// 防止路径遍历攻击，确保只删除 upload/ 目录中的文件
	filePath := filepath.Join("upload", filename)
	if !isPathSafe(filePath) {
		http.Error(w, "Invalid file path", http.StatusBadRequest)
		return
	}

	err := os.Remove(filePath)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	http.Redirect(w, r, "/", http.StatusFound)
}

func isPathSafe(filePath string) bool {
	absPath, err := filepath.Abs(filePath)
	if err != nil {
		return false
	}
	uploadDir, _ := filepath.Abs("upload")
	return filepath.HasPrefix(absPath, uploadDir)
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
	files, err := os.ReadDir("upload/")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	var fileNames []string
	for _, file := range files {
		if !file.IsDir() {
			fileNames = append(fileNames, file.Name())
		}
	}

	pageData := PageData{Files: fileNames}
	err = tmpl.Execute(w, pageData)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
